home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
- #-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
-
- # Utility functions.
- #
- # Copyright (C) 2000-2001 Ximian, Inc.
- #
- # Authors: Hans Petter Jansson <hpj@ximian.com>
- # Arturo Espinosa <arturo@ximian.com>
- # Michael Vogt <mvo@debian.org> - Debian 2.[2|3] support.
- # David Lee Ludwig <davidl@wpi.edu> - Debian 2.[2|3] support.
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU Library General Public License as published
- # by the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU Library General Public License for more details.
- #
- # You should have received a copy of the GNU Library General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-
-
- # --- Utilities for strings, arrays and other data structures --- #
-
- package Utils::Util;
-
- sub max
- {
- return ($_[0] > $_[1])? $_[0]: $_[1];
- }
-
- # Boolean <-> strings conversion.
-
- sub read_boolean
- {
- my ($v) = @_;
-
- return 1 if ($v =~ "true" ||
- $v =~ "yes" ||
- $v =~ "YES" ||
- $v =~ "on" ||
- $v eq "1");
- return 0;
- }
-
-
- sub print_boolean_yesno
- {
- if ($_[0] == 1) { return "yes"; }
- return "no";
- }
-
-
- sub print_boolean_truefalse
- {
- if ($_[0] == 1) { return "true"; }
- return "false";
- }
-
-
- sub print_boolean_onoff
- {
- if ($_[0] == 1) { return "on"; }
- return "off";
- }
-
-
- # Pushes a list to an array, only if it's not already in there.
- # I'm sure there's a smarter way to do this. Should only be used for small
- # lists, as it's O(N^2). Larger lists with unique members should use a hash.
-
- sub push_unique
- {
- my $arr = $_[0];
- my $found;
- my $i;
-
- # Go through all elements in pushed list.
-
- for ($i = 1; $_[$i]; $i++)
- {
- # Compare against all elements in destination array.
-
- $found = "";
- for $elem (@$arr)
- {
- if ($elem eq $_[$i]) { $found = $elem; last; }
- }
-
- if ($found eq "") { push (@$arr, $_[$i]); }
- }
- }
-
-
- # Merges scr array into dest array.
- sub arr_merge
- {
- my ($dest, $src) = @_;
- my (%h, $i);
-
- foreach $i (@$a, @$b)
- {
- $h{$i} = 1;
- }
-
- @$a = keys %h;
- return $a;
- }
-
- # Given an array and a pattern, it returns the index of the
- # array that contains it
- sub find_array_index
- {
- my($arrayRef, $pattern) = @_;
- my(@array) = @{$arrayRef};
- my($numElements) = scalar(@array);
- my(@indexes) = (0..$numElements);
- my(@elements);
-
- @elements = grep @{$arrayRef}[$_] =~ /$pattern/, @indexes;
- return(wantarray ? @elements : $elements[0]);
- }
-
-
- sub ignore_line
- {
- if (($_[0] =~ /^[ \t]*\#/) || ($_[0] =~ /^[ \t\n\r]*$/)) { return 1; }
- return 0;
- }
-
-
- # &gst_item_is_in_list
- #
- # Given:
- # * A scalar value.
- # * An array.
- # this function will return 1 if the scalar value is in the array, 0 otherwise.
-
- sub item_is_in_list
- {
- my ($value, @arr) = @_;
- my ($item);
-
- foreach $item (@arr)
- {
- return 1 if $value eq $item;
- }
-
- return 0;
- }
-
-
- # Recursively compare a structure made of nested arrays and hashes, diving
- # into references, if necessary. Circular references will cause a loop.
- # Watch it: arrays must have elements in the same order to be equal.
- sub struct_eq
- {
- my ($a1, $a2) = @_;
- my ($type1, $type2);
- my (@keys1, @keys2);
- my ($elem1, $elem2);
- my $i;
-
- $type1 = ref $a1;
- $type2 = ref $a2;
-
- return 0 if $type1 != $type2;
- return 1 if $a1 eq $a2;
- return 0 if (!$type1); # Scalars
-
- if ($type1 eq "SCALAR") {
- return 0 if $$a1 ne $$a2;
- }
- elsif ($type1 eq "ARRAY")
- {
- return 0 if $#$a1 != $#$a2;
-
- for ($i = 0; $i <= $#$a1; $i++)
- {
- return 0 if !&struct_eq ($$a1[$i], $$a2[$i]);
- }
- }
- elsif ($type1 eq "HASH") {
- @keys1 = sort keys (%$a1);
- @keys2 = sort keys (%$a2);
-
- return 0 if !&struct_eq (\@keys1, \@keys2);
- foreach $i (@keys1)
- {
- return 0 if !&struct_eq ($$a1{$i}, $$a2{$i});
- }
- }
- else
- {
- return 0;
- }
-
- return 1;
- }
-
-
- # &gst_get_key_for_subkeys
- #
- # Given:
- # * A hash-table with its values containing references to other hash-tables,
- # which are called "sub-hash-tables".
- # * A list of possible keys (stored as strings), called the "match_list".
- # this method will look through the "sub-keys" (the keys of each
- # sub-hash-table) seeing if one of them matches up with an item in the
- # match_list. If so, the key will be returned.
-
- sub get_key_for_subkeys
- {
- my %hash = %{$_[0]};
- my @match_list = @{$_[1]};
-
- foreach $key (keys (%hash))
- {
- my %subhash = %{$hash{$key}};
- foreach $item (@match_list)
- {
- if ($subhash{$item} ne "") { return $key; }
- }
- }
-
- return "";
- }
-
-
- # &gst_get_key_for_subkey_and_subvalues
- #
- # Given:
- # * A hash-table with its values containing references to other hash-tables,
- # which are called "sub-hash-tables". These sub-hash-tables contain
- # "sub-keys" with associated "sub-values".
- # * A sub-key, called the "match_key".
- # * A list of possible sub-values, called the "match_list".
- # this function will look through each sub-hash-table looking for an entry
- # whose:
- # * sub-key equals match_key.
- # * sub-key associated sub-value is contained in the match_list.
-
- sub get_key_for_subkey_and_subvalues
- {
- my %hash = %{$_[0]};
- my $key;
- my $match_key = $_[1];
- my @match_list = @{$_[2]};
-
- foreach $key (keys (%hash))
- {
- my %subhash = %{$hash{$key}};
- my $subvalue = $subhash{$match_key};
-
- if ($subvalue eq "") { next; }
-
- foreach $item (@match_list)
- {
- if ($item eq $subvalue) { return $key; }
- }
- }
-
- return "";
- }
-
-
- # --- IP calculation --- #
-
-
- # ip_calc_network (<IP>, <netmask>)
- #
- # Calculates the network address and returns it as a string.
-
- sub ip_calc_network
- {
- my @ip_reg1;
- my @ip_reg2;
-
- @ip_reg1 = ($_[0] =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
- @ip_reg2 = ($_[1] =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
-
- $ip_reg1[0] = ($ip_reg1[0] * 1) & ($ip_reg2[0] * 1);
- $ip_reg1[1] = ($ip_reg1[1] * 1) & ($ip_reg2[1] * 1);
- $ip_reg1[2] = ($ip_reg1[2] * 1) & ($ip_reg2[2] * 1);
- $ip_reg1[3] = ($ip_reg1[3] * 1) & ($ip_reg2[3] * 1);
-
- return join ('.', @ip_reg1);
- }
-
-
- # ip_calc_broadcast (<IP>, <netmask>)
- #
- # Calculates the broadcast address and returns it as a string.
-
- sub ip_calc_broadcast
- {
- my @ip_reg1;
- my @ip_reg2;
-
- @ip_reg1 = ($_[0] =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
- @ip_reg2 = ($_[1] =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
-
- @ip_reg1 = ($cf_hostip =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/);
-
- $ip_reg1[0] = ($ip_reg1[0] * 1) | (~($ip_reg2[0] * 1) & 255);
- $ip_reg1[1] = ($ip_reg1[1] * 1) | (~($ip_reg2[1] * 1) & 255);
- $ip_reg1[2] = ($ip_reg1[2] * 1) | (~($ip_reg2[2] * 1) & 255);
- $ip_reg1[3] = ($ip_reg1[3] * 1) | (~($ip_reg2[3] * 1) & 255);
-
- return join ('.', @ip_reg1);
- }
-
- # Forks a process, running $proc with @args in the child, and
- # printing the returned value of $proc in the pipe. Parent
- # returns a structure with useful data about the process.
- sub process_fork
- {
- my ($proc, @args) = @_;
- my $pid;
- local *PARENT_RDR;
- local *CHILD_WTR;
-
- pipe (PARENT_RDR, CHILD_WTR);
-
- $pid = fork ();
- if ($pid)
- {
- # Parent
- close CHILD_WTR;
- return {"pid" => $pid, "fd" => *PARENT_RDR, "fileno" => fileno (*PARENT_RDR)};
- }
- else
- {
- my $ret;
- close PARENT_RDR;
- # Child
- $ret = &$proc (@args);
- my $type = ref ($ret);
-
- if (!$type)
- {
- print CHILD_WTR $ret;
- }
- elsif ($type eq 'ARRAY')
- {
- print CHILD_WTR "$_\n" foreach (@$ret);
- }
-
- close CHILD_WTR;
- exit (0);
- }
- }
-
-
- # Close pipe, kill process, wait for it to finish.
- sub process_kill
- {
- my ($proc) = @_;
-
- &Utils::File::close_file ($$proc{"fd"});
- kill 2, $$proc{"pid"};
- waitpid ($$proc{"pid"}, undef);
- }
-
-
- # Populate a bitmap of the used file descriptors.
- sub process_list_build_fd_bitmap
- {
- my ($procs) = @_;
- my ($bits, $proc);
-
- foreach $proc (@$procs)
- {
- vec ($bits, $$proc{"fileno"}, 1) = 1;
- }
-
- return $bits;
- }
-
-
- # Receives a seconds timeout (may be float) and a ref to
- # a list of processes (each returned by gst_fork_process), and
- # set the "ready" key to true in all the procs that are ready
- # to return values, false otherwise. Returns time left before
- # timeout.
- sub process_list_check_ready
- {
- my ($timeout, $procs) = @_;
- my ($bits, $bitsleft, $bitsready, $timestamp, $timeleft);
-
- $procs = [ $procs ] if ref ($procs) ne 'ARRAY';
- $bits = &process_list_build_fd_bitmap ($procs);
-
- # Check with timeout which descriptors are ready with info.
- $timeout = undef if $timeout == 0;
- $timeleft = $timeout;
- $bitsleft = $bits;
- while (($timeout eq undef) || ($timeleft > 0))
- {
- $timestamp = time;
- select ($bitsleft, undef, undef, $timeleft);
- $timeleft -= time - $timestamp if $timeout ne undef;
-
- $bitsready |= $bitsleft;
- $bitsleft = $bits & (~$bitsready);
- last if $bitsready eq $bits;
- }
- $bits = $bitsready;
-
- # For every process, set "ready" key to 1/0 depending on
- # its file descriptor bit.
- foreach $proc (@$procs)
- {
- $$proc{"ready"} = (ord ($bits) & (1 << $$proc{"fileno"}))? 1 : 0;
- }
-
- return $timeleft;
- }
-
-
- sub process_result_collect
- {
- my ($proc, $func, @args) = @_;
- my ($value, $tmp, $lines);
-
- if ($$proc{"ready"})
- {
- my @list;
-
- $lines .= $tmp while (sysread ($$proc{"fd"}, $tmp, 4096));
- goto PROC_KILL unless $lines;
- if ($lines =~ /\n/)
- {
- @list = split ("\n", $lines);
- }
- else
- {
- push @list, $line;
- }
-
- $value = &$func (\@list, @args);
- }
-
- PROC_KILL:
- &process_kill ($proc);
-
- return $value;
- }
-
-
- 1;
-